home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 4 / MacMania 4.toast / / Demo's / Igor Demo Pro / 1 PutContentsIn Igor Pro Folder / WaveMetrics Procedures / Analysis / Peak Fitting / Multi-peak fitting 1.2 next >
Text File  |  1996-01-30  |  44KB  |  1,627 lines

  1. //    Multi-peak fitting
  2. //        Version 1.20
  3. //
  4. //    Changes since 1.10
  5. //        Fixed problem when x axis reversed
  6. //        Control panel permits unlimited peaks.
  7. //        Fixed bug involving parameters not updating after Lorentzian fit
  8. //        Made Igor Pro 3.0 savvy (Data Folder and liberal name aware)
  9. //        Used Data Folders to allow easy fitting to several subranges of data with revisiting
  10. //    Changes since 1.00
  11. //        Added display of individual fitted peaks
  12. //        Added RunMeAfterManualFit() macro which updates the panel and graph
  13. //
  14. //    Note: if you don't have (or can't use) the XFUNCs contained in the
  15. //    GaussFit, LorentzianFit and VoigtFit XOP modules, use the following #include line
  16. //    in your Procedure window to obtain access to the user defined versions of the fitting funcitions.
  17. //    Then uncheck the "Use XFUNCs" checkbox in the panel.
  18. //    #include <Peak Functions>
  19. //
  20. //    Note: Instructions are in the "Multi-peak Fit" experiment in the Examples:Curve Fitting
  21. //    folder. That experiment also contains sample data and a guided tour.
  22. //
  23. //    You can make some sample data like so:
  24. //        Make/N=500 data;SetScale x,300e-9,500e-9,"m" data
  25. //        data= exp(-((x-380e-9)/20e-9)^2) + 0.5*exp(-((x-430e-9)/30e-9)^2) + gnoise(0.02)
  26. //
  27. //    The package creates its results, waves and variables, in a new data folder it creates in
  28. //    the DF containing your data (which needs to be the current DF (CDF)). The folder name
  29. //    is WMPeakFits. Within that DF are individual data folders for each sub-range of data you
  30. //    create. When it is the currently active set, the data folder is named Current
  31. //    When you want to freeze the results of a run, you can rename this DF to anything ohter than Current.
  32. //    That is done for you by the RenameGroup macro.
  33. //
  34. // The master wave (called mw here but is really named masterCoef) has the following structure:
  35. //    mw[0] & mw[1] contain the center and width of the x range for use in basline calcs
  36. //    mw[2-5] contain the coefficeints of a cubic poly using x values scaled with mw[0-1]
  37. //    mw[6]= amp of first peak
  38. //    mw[7]= position of first peak
  39. //    mw[8]= width of first peak
  40. //    mw[9]= shape factor for voigt for first peak
  41. //    mw[10-13]= coefs for 2nd peak
  42. //    etc.
  43.  
  44. #pragma rtGlobals= 1
  45.  
  46. Function WMCreateFitGlobals()
  47.     String dfSav= GetDataFolder(1)
  48.     
  49.     NewDataFolder/O/S root:Packages
  50.     NewDataFolder/O/S WMmpFitting
  51.     
  52.     Variable/G     gChiSquare
  53.     Variable/G gSaveSet
  54.  
  55.     Variable/G gDoBaseline,g1Width,g1Shape,gCurPeak,gNumPeaks,gFitType
  56.     Variable/G gPeakAmp,gPeakPos,gPeakWidth,gVoigtShape,gUseXFUNCs
  57.     Variable/G gPeakWidthFactor
  58.     String/G gYDataName,gFitDataName,gXDataName,gResidsName
  59.     String/G gCurDataFolder        // the DF containing the current data set
  60.     SetDataFolder dfSav
  61. end
  62.  
  63. Macro CreateFitSetupPanel()
  64.     DoWindow/F FitSetupPanel
  65.     if(!V_Flag )
  66.         WMCreateFitGlobals()
  67.         FitSetupPanel()
  68.     endif
  69. end
  70.  
  71. Macro UseCursors()
  72.     if( exists(":WMPeakFits:Current:masterCoef")==0 )
  73.         DoAlert 0,"First, use the Set button in the FitSetupPanel"
  74.         return
  75.     endif
  76.  
  77.     DoWindow/F $WinName(0, 1)
  78.     root:Packages:WMmpFitting:gCurPeak=1
  79.     ControlBar 35
  80.     Button gb0,pos={30,6},size={80,20},proc=ProcNextPeak,title="Next Peak"
  81.     Button gb1,pos={118,6},size={50,20},proc=BProcFromCsrs,title="Set"
  82.     Button gb2,pos={256,8},size={50,20},proc=BProcDone,title="Done"
  83.     UpdateCurSettings()
  84.     SetCursorsForCurPeak()
  85. end
  86.  
  87. Macro ZapFitAndResiduals()
  88.     Silent 1; PauseUpdate
  89.  
  90.     if( (exists("root:Packages:WMmpFitting:gFitDataName")==0) * (exists("root:Packages:WMmpFitting:gResidsName")==0) )
  91.         return
  92.     endif
  93.     $root:Packages:WMmpFitting:gFitDataName= NaN
  94.     $root:Packages:WMmpFitting:gResidsName= NaN
  95. end
  96.  
  97. Macro RenameGroup(gname)
  98.     String gname= StrVarOrDefault(":WMPeakFits:Current:prefix","GroupA")
  99.     Prompt gname,"name for this group of result waves:"
  100.     
  101.     Silent 1; PauseUpdate
  102.     
  103.     if( !DataFolderExists(":WMPeakFits:Current") )
  104.         DoAlert 0,"First, generate some results."
  105.         return
  106.     endif
  107.     if( DataFolderExists(":WMPeakFits:"+gname) )
  108.         DoAlert 0,"Sorry, that name is already taken."
  109.         return
  110.     endif
  111.     String/G :WMPeakFits:Current:prefix= gname
  112.     RenameDataFolder :WMPeakFits:Current,$gname
  113. end
  114.  
  115. Function/S WMPF_DataFolderList(theDF)
  116.     String theDF
  117.     
  118.     String dfSav= GetDataFolder(1)
  119.     if( strlen(theDF)!=0 )
  120.         SetDataFolder theDF
  121.     endif
  122.     Variable i=0
  123.     String s="",dfname
  124.     do
  125.         dfName= GetIndexedObjName("", 4, i)
  126.         if( strlen(dfName)==0 )
  127.             break
  128.         endif
  129.         s+=dfname+";"
  130.         i+=1
  131.     while(1)
  132.     SetDataFolder dfSav
  133.     return s
  134. end
  135.  
  136.  
  137.  
  138. // Find topmost graph containing given wave
  139. //    returns zero length string if not found
  140. //
  141. Function/S FindGraphWithWave(w)
  142.     wave w
  143.     
  144.     string win=""
  145.     variable i=0
  146.     
  147.     do
  148.         win=WinName(i, 1)                // name of ith graph window
  149.         if( strlen(win) == 0 )
  150.             break;                            // no more graph wndows
  151.         endif
  152.         CheckDisplayed/W=$win  w
  153.         if(V_Flag)
  154.             break
  155.         endif
  156.         i += 1
  157.     while(1)
  158.     return win
  159. end
  160.  
  161. Function ReturnToOldDataSet(gname)
  162.     String gname    // contains desired group name. May be Current or a renamed set (or bogus)
  163.     
  164.     if( !exists(":WMPeakFits:yDataName") )
  165.         DoAlert 0,"Fit info not found. Did you choose the wrong data folder?"
  166.         return 1
  167.     endif
  168.     
  169.     SVAR gCurDataFolder= root:Packages:WMmpFitting:gCurDataFolder
  170.     gCurDataFolder= GetDataFolder(1)
  171.  
  172.     SVAR yDataName= :WMPeakFits:yDataName    // when we first did a set, we squirreled away the name of the data here (I hope the term squirreled does not offend any rodent-americans)
  173.     SVAR xDataName= :WMPeakFits:xDataName
  174.  
  175.     SVAR gYDataName= root:Packages:WMmpFitting:gYDataName
  176.     SVAR gXDataName= root:Packages:WMmpFitting:gXDataName
  177.     SVAR gFitDataName= root:Packages:WMmpFitting:gFitDataName
  178.     SVAR gResidsName= root:Packages:WMmpFitting:gResidsName
  179.     
  180.     gYDataName= yDataName
  181.     gXDataName= xDataName
  182.     gFitDataName= "fit_"+gYDataName
  183.     gResidsName= "res_"+gYDataName
  184.     
  185.     String grfname= FindGraphWithWave($gFitDataName)
  186.     if( strlen(grfname) != 0 )
  187.         DoWindow/F $grfname
  188.     endif
  189.     DoWindow/F FitSetupPanel
  190.  
  191.     PopupMenu popupYData,win=FitSetupPanel,mode=1,popvalue=yDataName    // mode value has to be non-zero but we don't know the actual number
  192.     PopupMenu popupXData,win=FitSetupPanel,mode=2,popvalue=xDataName
  193.  
  194.     if( CmpStr(gname,"Current") == 0 )
  195.         UpdateCurSettings();CalculateData()
  196.     endif
  197.     return 0
  198. end
  199.  
  200. Macro RevisitGroup(gname)
  201.     String gname= "GroupA"
  202.     Prompt gname,"Data Folder containing group of result waves:",popup WMPF_DataFolderList("WMPeakFits")
  203.     
  204.     Silent 1; PauseUpdate
  205.  
  206.     if( CmpStr(GetDataFolder(1),root:Packages:WMmpFitting:gCurDataFolder) != 0 )    // returning from a different data set?
  207.         if( ReturnToOldDataSet(gname) )
  208.             return                        // error
  209.         endif
  210.     endif
  211.  
  212.     if( CmpStr(gname,"Current") == 0 )
  213.         ResetAxisRange()
  214.         return
  215.     endif
  216.     
  217.     if( DataFolderExists(":WMPeakFits:Current") )        //Switching to a different setup but haven't saved the old one yet. Try to do it automatically.
  218.         String s
  219.         if( exists(":WMPeakFits:Current:prefix") )        // look for possible old name
  220.             s= :WMPeakFits:Current:prefix
  221.         else
  222.             s= "oldCurrent"
  223.         endif
  224.         if( DataFolderExists("WMPeakFits:"+s) )
  225.             DoAlert 0,"Can't rename Current due to conflict. You'll need to do it yourself."
  226.             return
  227.         endif
  228.         RenameDataFolder :WMPeakFits:Current,$s
  229.     endif
  230.             
  231.     RenameDataFolder $":WMPeakFits:"+gname,Current
  232.     UpdateCurSettings();CalculateData();ResetAxisRange()
  233. end
  234.  
  235. Macro RunMeAfterManualFit()
  236.     if( exists(":WMPeakFits:Current:masterCoef")==0 )
  237.         DoAlert 0,"First, use the Set button in the FitSetupPanel"
  238.         return
  239.     endif
  240.     if( exists(":WMPeakFits:Current:coef")==0 )
  241.         DoAlert 0,"First, copy the coef wave to the Current data folder"
  242.         return
  243.     endif
  244.  
  245.     UpdateMasterCoef();UpdateCurSettings();CalculateData()
  246. end
  247.  
  248. Macro PrintPeakParams()
  249.     Silent 1
  250.     
  251.     String func= ""
  252.     Variable fitType= root:Packages:WMmpFitting:gFitType
  253.  
  254.     if( fitType==0 )    // Gaussian = k0*exp(-((x-k1)/k2)^2)
  255.         func= "Gaussian"
  256.     endif
  257.     if( fitType==1 )    // Lorentzian = k0*/( (x-k1)^2 + k2 )
  258.         func= "Lorentzian"
  259.     endif
  260.     if( fitType==2 )    // VoigtFit = k0*Voigt(k1*(x-k2),k3)
  261.         func= "Voigt"
  262.     endif
  263.     printf "For %s peaks:\r",func
  264.  
  265.     Variable i=0,pos,width,amp,shape,area,wg,wl
  266.     do
  267.         pos= :WMPeakFits:Current:masterCoef[6+4*i+1]                // position of peak
  268.         if( root:Packages:WMmpFitting:g1Width )
  269.             width= :WMPeakFits:Current:masterCoef[8]                // width of first peak
  270.         else
  271.             width= :WMPeakFits:Current:masterCoef[8+4*i]            // width of this peak
  272.         endif
  273.         
  274.         amp= CalcAmpFromMC(i,$":WMPeakFits:Current:masterCoef")
  275.         width= CalcWidthFromMC(i,$":WMPeakFits:Current:masterCoef")
  276.         shape= CalcShapeFromMC(i,$":WMPeakFits:Current:masterCoef")
  277.  
  278.         if( fitType==0 )    // Gaussian = k0*exp(-((x-k1)/k2)^2)
  279.             area= amp*width*sqrt(Pi)
  280.             width *= 2*sqrt(ln(2))
  281.         endif
  282.         if( fitType==1 )    // Lorentzian = k0*/( (x-k1)^2 + k2 )
  283.             area= Pi*amp/sqrt(width)
  284.             width= 2*sqrt(width)
  285.         endif
  286.         if( fitType==2 )    // VoigtFit = k0*Voigt(k1*(x-k2),k3)
  287.             area= amp*sqrt(pi)/width
  288.             wg= sqrt(ln(2))/width    // gaussian width
  289.             wl= shape/width             // lorentzian width
  290.             width= wl/2 + sqrt( wl^2/4 + wg^2)
  291.             width *=2    // the above were half width at half max and we report fwhm
  292.             wg *= 2
  293.             wl *= 2
  294.         endif
  295.         printf "Peak#%d: position= %g, area= %g, width (fwhm)= %g\r",i+1,pos,area,width
  296.         if( fitType==2 )    // VoigtFit = k0*Voigt(k1*(x-k2),k3)
  297.             printf "\t Gaussian width= %g, Lorentzian width= %g, shape= %g\r",wg,wl,shape
  298.         endif
  299.         i += 1
  300.     while(i<root:Packages:WMmpFitting:gNumPeaks)
  301. end
  302.  
  303.  
  304.  
  305. Macro RemovePeakPackage()
  306.     if( strlen(WinList("FitSetupPanel",";","")) != 0 )
  307.         DoWindow/K FitSetupPanel
  308.     endif
  309.     KillDataFolder root:Packages:WMmpFitting
  310.     DoAlert 0,"Now remove the #include from your Procedure window and recompile"
  311. end
  312.  
  313.  
  314. Function CheckPeakPackage()
  315.     if( exists(":WMPeakFits:Current:masterCoef")==1 )
  316.         return 0
  317.     endif
  318.     DoAlert 0,"Click the Setup button first"
  319.     return 1
  320. end
  321.  
  322.  
  323. Function SetCursorsForCurPeak()
  324.     NVAR gCurPeak= root:Packages:WMmpFitting:gCurPeak
  325.     SVAR gXDataName= root:Packages:WMmpFitting:gXDataName
  326.     SVAR gYDataName= root:Packages:WMmpFitting:gYDataName
  327.  
  328.     Variable apnum,bpnum,axval,bxval,i=6+4*(gCurPeak-1)
  329.     Wave w= $":WMPeakFits:Current:mastercoef"
  330.     axval= w[i+1]
  331.     bxval= axval+w[i+2]
  332.     if(  cmpstr(gXDataName,"_calculated_") == 0 )
  333.         apnum= x2pnt($gYDataName, axval)
  334.         bpnum= x2pnt($gYDataName, bxval)
  335.     else
  336.         apnum= BinarySearch($gXDataName,axval)
  337.         bpnum= BinarySearch($gXDataName,bxval)
  338.     endif
  339.     Cursor/P A,$gYDataName,apnum
  340.     Cursor/P B,$gYDataName,bpnum
  341. end
  342.  
  343.  
  344. Function BProcFromCsrs(ctrlName) : ButtonControl
  345.     String ctrlName
  346.  
  347.     NVAR gCurPeak= root:Packages:WMmpFitting:gCurPeak
  348.     wave w= $":WMPeakFits:Current:masterCoef"
  349.     Variable i= 6+4*(gCurPeak-1)
  350.     w[i]= vcsr(A)
  351.     w[i+1]= hcsr(A)
  352.     w[i+2]= abs(hcsr(A)-hcsr(B))
  353.     CalculateData()
  354.     UpdateCurSettings()
  355. End
  356.  
  357.  
  358. Function CalcAmpFromMC(pknum,master)
  359.     Variable pknum
  360.     Wave master
  361.  
  362.     NVAR gFitType= root:Packages:WMmpFitting:gFitType
  363.     NVAR g1Shape= root:Packages:WMmpFitting:g1Shape
  364.     NVAR g1Width= root:Packages:WMmpFitting:g1Width
  365.     
  366.     Variable j= 6+4*pknum            // index to first peak's coefs (amp)
  367.  
  368.     if( gFitType==0 )    // Gaussian = k0*exp(-((x-k1)/k2)^2)
  369.         return master[j]
  370.     endif
  371.  
  372.     if( gFitType==1 )    // Lorentzian = k0*/( (x-k1)^2 + k2 )
  373.         if( g1Width  )
  374.             return master[j]*master[8]^2
  375.         else
  376.             return  master[j]*master[j+2]^2
  377.         endif
  378.     endif
  379.  
  380.     if( gFitType==2 )    // VoigtFit = k0*Voigt(k1*(x-k2),k3)
  381.         Variable shape= master[9]
  382.         if( g1Shape  == 0 )
  383.             shape= master[j+3]
  384.         endif
  385.         return master[j]*(1+ shape)
  386.     endif
  387.     return NaN
  388. end
  389.  
  390.  
  391. Function CalcWidthFromMC(pknum,master)
  392.     Variable pknum
  393.     Wave master
  394.     
  395.     NVAR gFitType= root:Packages:WMmpFitting:gFitType
  396.     NVAR g1Shape= root:Packages:WMmpFitting:g1Shape
  397.     NVAR g1Width= root:Packages:WMmpFitting:g1Width
  398.  
  399.     Variable j= 6+4*pknum            // index to first peak's coefs (amp)
  400.  
  401.     if( gFitType==0 )    // Gaussian = k0*exp(-((x-k1)/k2)^2)
  402.         if( g1Width  )
  403.             return master[8]
  404.         else
  405.             return master[j+2]
  406.         endif
  407.     endif
  408.  
  409.     if( gFitType==1 )    // Lorentzian = k0*/( (x-k1)^2 + k2 )
  410.         if( g1Width  )
  411.             return master[8]^2
  412.         else
  413.             return  master[j+2]^2
  414.         endif
  415.     endif
  416.  
  417.     if( gFitType==2 )    // VoigtFit = k0*Voigt(k1*(x-k2),k3)
  418.         Variable shape= master[9]
  419.         if( g1Shape  == 0 )
  420.             shape= master[j+3]
  421.         endif
  422.         if( g1Width  )
  423.             return (1+ shape)/master[8]
  424.         else
  425.             return   (1+ shape)/master[j+2]
  426.         endif
  427.     endif
  428.     return NaN
  429. end
  430.  
  431.  
  432. Function CalcShapeFromMC(pknum,master)
  433.     Variable pknum
  434.     Wave master
  435.  
  436.     Variable j= 6+4*pknum            // index to first peak's coefs (amp)
  437.  
  438.     NVAR gFitType= root:Packages:WMmpFitting:gFitType
  439.     NVAR g1Shape= root:Packages:WMmpFitting:g1Shape
  440.  
  441.     if( gFitType==2 )    // VoigtFit = k0*Voigt(k1*(x-k2),k3)
  442.         Variable shape= master[9]
  443.         if( g1Shape  == 0 )
  444.             shape= master[j+3]
  445.         endif
  446.         return shape
  447.     endif
  448.     return 1
  449. end
  450.  
  451.  
  452.  
  453. Function CalculateCoef()
  454.     Wave master= $":WMPeakFits:Current:masterCoef"
  455.     Wave masterHold= $":WMPeakFits:Current:masterCoefHold"
  456.     
  457.     NVAR gFitType= root:Packages:WMmpFitting:gFitType
  458.     NVAR g1Shape= root:Packages:WMmpFitting:g1Shape
  459.     NVAR g1Width= root:Packages:WMmpFitting:g1Width
  460.     NVAR gDoBaseline= root:Packages:WMmpFitting:gDoBaseline
  461.  
  462.     Variable i,nc,j, npks= (numpnts(master)-6)/4
  463.  
  464.     if( (gFitType==0) %| (gFitType==1) )    // Gaussian or Lorentzian
  465.         nc= 1+gDoBaseline*5+g1Width+npks*(3-g1Width)
  466.     else // must be Voigt for now
  467.         nc= 1+gDoBaseline*5+g1Width+g1Shape+npks*(4-g1Width-g1Shape)
  468.     endif
  469.     Duplicate/O master,$":WMPeakFits:Current:coef"
  470.     Duplicate/O masterHold,$":WMPeakFits:Current:coefHold"
  471.     Wave slave= $":WMPeakFits:Current:coef"
  472.     Wave slaveHold= $":WMPeakFits:Current:coefHold"
  473.     Redimension/N=(nc) slave,slaveHold
  474.     if( gDoBaseline )
  475.         slave[0,5]= master[P]                // copy baseline
  476.         slaveHold[0,5]= masterHold[P]    
  477.         i= 6
  478.     else
  479.         slave[0]= master[2]        // copy only offset
  480.         slaveHold[0]= masterHold[2]    
  481.         i=1
  482.     endif
  483.     do
  484.         if( gFitType==0 )    // Gaussian = k0*exp(-((x-k1)/k2)^2)
  485.             if( g1Width )
  486.                 slave[i]= master[8]
  487.                 slaveHold[i]= masterHold[8]    
  488.                 i+=1
  489.             endif
  490.             j= 6
  491.             do
  492.                 slave[i]= master[j]
  493.                 slaveHold[i]= masterHold[j]    
  494.                 i+=1
  495.                 slave[i]= master[j+1]
  496.                 slaveHold[i]= masterHold[j+1]    
  497.                 i+=1
  498.                 if( g1Width == 0 )
  499.                     slave[i]= master[j+2]
  500.                     slaveHold[i]= masterHold[j+2]
  501.                     i+=1
  502.                 endif
  503.                 j += 4                        // each peak has 4 parameters (not all used)
  504.             while(i<nc)
  505.             break
  506.         endif
  507.         if( gFitType==1 )    // Lorentzian = k0*/( (x-k1)^2 + k2 )
  508.             if( g1Width )
  509.                 slave[i]= master[8]^2
  510.                 slaveHold[i]= masterHold[8]
  511.                 i+=1
  512.             endif
  513.             j= 6
  514.             do
  515.                 if( g1Width  )
  516.                     slave[i]= master[j]*master[8]^2
  517.                 else
  518.                     slave[i]= master[j]*master[j+2]^2
  519.                 endif
  520.                 slaveHold[i]= masterHold[j]
  521.                 i+=1
  522.                 slave[i]= master[j+1]
  523.                 slaveHold[i]= masterHold[j+1]
  524.                 i+=1
  525.                 if( g1Width == 0 )
  526.                     slave[i]= master[j+2]^2
  527.                     slaveHold[i]= masterHold[j+2]
  528.                     i+=1
  529.                 endif
  530.                 j += 4                        // each peak has 4 parameters (not all used)
  531.             while(i<nc)
  532.             break
  533.         endif
  534.         if( gFitType==2 )    // VoigtFit = k0*Voigt(k1*(x-k2),k3)
  535.             variable shape,width
  536.             if(  g1Shape )
  537.                 slave[i]= master[9]        // 1 Shape or 1 Shape and 1 Width
  538.                 slaveHold[i]= masterHold[9]
  539.                 shape= master[9]
  540.                 i+=1
  541.             endif
  542.             if( g1Width )
  543.                 slave[i]= (1+ master[9])/master[8]
  544.                 slaveHold[i]= masterHold[8]
  545.                 width= master[8]
  546.                 i+=1
  547.             endif
  548.             j= 6
  549.             do
  550.                 if( g1Shape  == 0 )
  551.                     shape= master[j+3]
  552.                 endif
  553.                 if( g1Width == 0 )
  554.                     width= master[j+2]
  555.                 endif
  556.                 slave[i]= master[j]*(1+ shape)
  557.                 slaveHold[i]= masterHold[j]
  558.                 i+=1
  559.                 if( g1Width == 0 )
  560.                     slave[i]=(1+ shape)/width
  561.                     slaveHold[i]= masterHold[j+2]
  562.                     i+=1
  563.                 endif
  564.                 slave[i]= master[j+1]
  565.                 slaveHold[i]= masterHold[j+1]
  566.                 i+=1
  567.                 if(  g1Shape == 0 )
  568.                     slave[i]= master[j+3]
  569.                     slaveHold[i]= masterHold[j+3]
  570.                     i+=1
  571.                 endif
  572.                 j += 4                        // each peak has 4 parameters (not all used)
  573.             while(i<nc)
  574.             break
  575.         endif
  576.     while(0)
  577. end
  578.  
  579. Function UpdateMasterCoef()
  580.     Wave master= $":WMPeakFits:Current:masterCoef"
  581.     Wave slave= $":WMPeakFits:Current:coef"
  582.     
  583.     NVAR gFitType= root:Packages:WMmpFitting:gFitType
  584.     NVAR g1Shape= root:Packages:WMmpFitting:g1Shape
  585.     NVAR g1Width= root:Packages:WMmpFitting:g1Width
  586.     NVAR gDoBaseline= root:Packages:WMmpFitting:gDoBaseline
  587.  
  588.     Variable i,nc,j, npks= (numpnts(master)-6)/4
  589.  
  590.     if( (gFitType==0) %| (gFitType==1) )    // Gaussian or Lorentzian
  591.         nc= 1+gDoBaseline*5+g1Width+npks*(3-g1Width)
  592.     else // must be Voigt for now
  593.         nc= 1+gDoBaseline*5+g1Width+g1Shape+npks*(4-g1Width-g1Shape)
  594.     endif
  595.     if( gDoBaseline )
  596.         master[0,5]= slave[P]        // copy baseline
  597.         i= 6
  598.     else
  599.         master[2]= slave[0]        // copy only offset
  600.         i=1
  601.     endif
  602.     do
  603.         if( gFitType==0 )    // Gaussian = k0*exp(-((x-k1)/k2)^2)
  604.             if( g1Width )
  605.                 master[8]= slave[i]
  606.                 i+=1
  607.             endif
  608.             j= 6
  609.             do
  610.                 master[j]= slave[i]
  611.                 i+=1
  612.                 master[j+1]= slave[i]
  613.                 i+=1
  614.                 if( g1Width == 0 )
  615.                     master[j+2]= slave[i]
  616.                     i+=1
  617.                 endif
  618.                 j += 4                        // each peak has 4 parameters (not all used)
  619.             while(i<nc)
  620.             break
  621.         endif
  622.         if( gFitType==1 )    // Lorentzian = k0*/( (x-k1)^2 + k2 )
  623.             if( g1Width )
  624.                 master[8]= sqrt(slave[i])
  625.                 i+=1
  626.             endif
  627.             j= 6
  628.             do
  629.                 if( g1Width  )
  630.                     master[j]=slave[i]/(master[8]^2)
  631.                 else
  632.                     master[j]=slave[i]/slave[i+2]
  633.                 endif
  634.                 i+=1
  635.                 master[j+1]= slave[i]
  636.                 i+=1
  637.                 if( g1Width == 0 )
  638.                     master[j+2]= sqrt(slave[i])
  639.                     i+=1
  640.                 endif
  641.                 j += 4                        // each peak has 4 parameters (not all used)
  642.             while(i<nc)
  643.             break
  644.         endif
  645.         if( gFitType==2 )    // VoigtFit = k0*Voigt(k1*(x-k2),k3)
  646.             variable shape,width
  647.             if(  g1Shape )
  648.                 master[9]= slave[i]        // 1 Shape or 1 Shape and 1 Width
  649.                 shape= master[9]
  650.                 i+=1
  651.             endif
  652.             if( g1Width )
  653.                 master[8]=(1+ shape)/ slave[i]
  654.                 width=  slave[i]
  655.                 i+=1
  656.             endif
  657.             j= 6
  658.             do
  659.                 if( g1Width == 0 )
  660.                     width= slave[i+1]
  661.                     if( g1Shape  == 0 )
  662.                         shape= slave[i+3]
  663.                     endif
  664.                 endif
  665.                 master[j]= slave[i]/(1+ shape)
  666.                 i+=1
  667.                 if( g1Width == 0 )
  668.                     master[j+2]= (1+ shape)/slave[i]
  669.                     i+=1
  670.                 endif
  671.                 master[j+1]= slave[i]
  672.                 i+=1
  673.                 if(  g1Shape == 0 )
  674.                     master[j+3]= slave[i]
  675.                     i+=1
  676.                 endif
  677.                 j += 4                        // each peak has 4 parameters (not all used)
  678.             while(i<nc)
  679.             break
  680.         endif
  681.     while(0)
  682. end
  683.     
  684.  
  685. Function CalculateData()
  686.      CalculateCoef()
  687.      
  688.     NVAR gFitType= root:Packages:WMmpFitting:gFitType
  689.     NVAR g1Shape= root:Packages:WMmpFitting:g1Shape
  690.     NVAR g1Width= root:Packages:WMmpFitting:g1Width
  691.     NVAR gDoBaseline= root:Packages:WMmpFitting:gDoBaseline
  692.     NVAR gUseXFUNCs= root:Packages:WMmpFitting:gUseXFUNCs
  693.  
  694.      String func=""
  695.  
  696.     if( gFitType==0 )    // Gaussian = k0*exp(-((x-k1)/k2)^2)
  697.         if( gDoBaseline )
  698.             if( g1Width )
  699.                 func= "GaussFit1WidthBL"
  700.             else
  701.                 func= "GaussFitBL"
  702.             endif
  703.         else
  704.             if( g1Width )
  705.                 func= "GaussFit1Width"
  706.             else
  707.                 func= "GaussFit"
  708.             endif
  709.         endif
  710.     endif
  711.     if( gFitType==1 )    // Lorentzian = k0*/( (x-k1)^2 + k2 )
  712.         if( gDoBaseline )
  713.             if( g1Width )
  714.                 func= "LorentzianFit1WidthBL"
  715.             else
  716.                 func= "LorentzianFitBL"
  717.             endif
  718.         else
  719.             if( g1Width )
  720.                 func= "LorentzianFit1Width"
  721.             else
  722.                 func= "LorentzianFit"
  723.             endif
  724.         endif
  725.     endif
  726.     if( gFitType==2 )    // VoigtFit = k0*Voigt(k1*(x-k2),k3)
  727.         if( gDoBaseline )
  728.             if( g1Width )    // implies 1 Shape also
  729.                 func= "VoigtFit1Shape1WidthBL"
  730.             else
  731.                 if( g1Shape )
  732.                     func= "VoigtFit1ShapeBL"
  733.                 else
  734.                     func= "VoigtFitBL"
  735.                 endif
  736.             endif
  737.         else
  738.             if( g1Width )    // implies 1 Shape also
  739.                 func= "VoigtFit1Shape1Width"
  740.             else
  741.                 if( g1Shape )
  742.                     func= "VoigtFit1Shape"
  743.                 else
  744.                     func= "VoigtFit"
  745.                 endif
  746.             endif
  747.         endif
  748.     endif
  749.     if( gUseXFUNCs == 0 )
  750.         func= "f"+func
  751.     endif
  752.  
  753.     SVAR gXDataName= root:Packages:WMmpFitting:gXDataName
  754.     SVAR gYDataName= root:Packages:WMmpFitting:gYDataName
  755.     SVAR gResidsName= root:Packages:WMmpFitting:gResidsName
  756.     SVAR gFitDataName= root:Packages:WMmpFitting:gFitDataName
  757.     NVAR gChiSquare= root:Packages:WMmpFitting:gChiSquare
  758.     
  759.     NVAR gRangeBegin= :WMPeakFits:Current:gRangeBegin
  760.     NVAR gRangeEnd= :WMPeakFits:Current:gRangeEnd
  761.  
  762.     String dfSav= GetDataFolder(1)
  763.     SetDataFolder :WMPeakFits:Current
  764.     
  765.     Wave dy= :::$gYDataName
  766.     Wave fw= :::$gFitDataName
  767.     Wave rw= :::$gResidsName
  768.  
  769.     String xn= "x"
  770.     if(  cmpstr(gXDataName,"_calculated_") != 0 )
  771.         xn= PossiblyQuoteName(gXDataName)
  772.     endif
  773.     String cmd
  774.     sprintf cmd,"%s[%g,%g]=%s(:WMPeakFits:Current:coef,%s)", ":::"+PossiblyQuoteName(gFitDataName),gRangeBegin,gRangeEnd,func,xn
  775. //print cmd
  776.     Execute cmd        // fitwave[begin,end]= func(coef,xsrc)
  777.  
  778.     SetDataFolder dfSav
  779.  
  780.     rw[gRangeBegin,gRangeEnd]= dy-fw
  781.  
  782.     gChiSquare= CalcChiSqr(rw)
  783.     UpdateIndividualPeaks()
  784. end
  785.  
  786. Function/S FindTraceUsingWave(w)
  787.     Wave w
  788.     
  789.     Variable i=0
  790.     do
  791.         String tracename= PossiblyQuoteName(NameOfWave(w))+"#"+num2istr(i)
  792.         Wave wt= TraceNameToWaveRef("", tracename)
  793.         if( WaveExists(wt) == 0 )
  794.             break
  795.         endif
  796.         if( CmpStr(GetWavesDataFolder(w, 4),GetWavesDataFolder(wt, 4)) == 0 )
  797.             return tracename
  798.         endif
  799.         i+=1
  800.     while(1)        // will exit above if trace found
  801.     return ""
  802. end
  803.     
  804.  
  805.  
  806.  
  807. Function TrimExcessPeaks()
  808.     String bname= "Peak",fname,tname                // basename for individual peak waves, full name, trace name
  809.     NVAR gNumPeaks= root:Packages:WMmpFitting:gNumPeaks
  810.     Variable i= gNumPeaks
  811.     do
  812.         tname= bname+num2istr(i+1)            // count from 1 rather than zero
  813.         Wave w=$":WMPeakFits:Current:"+tname
  814.         if( WaveExists(w)==0 )
  815.             break                                // quit when we run out of waves of this name series
  816.         endif
  817.         tname= FindTraceUsingWave(w)
  818.         if( strlen(tname) != 0 )
  819.             RemoveFromGraph $tname
  820.         endif
  821.         KillWaves w
  822.         i += 1
  823.     while(1)
  824. end
  825.  
  826.  
  827. Function UpdateIndividualPeaks()
  828.     NVAR gPeakWidthFactor= root:Packages:WMmpFitting:gPeakWidthFactor
  829.     NVAR g1Width= root:Packages:WMmpFitting:g1Width
  830.     NVAR gFitType= root:Packages:WMmpFitting:gFitType
  831.     NVAR gUseXFUNCs= root:Packages:WMmpFitting:gUseXFUNCs
  832.     NVAR gNumPeaks= root:Packages:WMmpFitting:gNumPeaks
  833.     SVAR gYDataName= root:Packages:WMmpFitting:gYDataName
  834.  
  835.     NVAR gXMin= :WMPeakFits:Current:gXMin
  836.     NVAR gXMax= :WMPeakFits:Current:gXMax
  837.     
  838.     if( gPeakWidthFactor < 0 )            // flag not to do peaks at all
  839.         return 0
  840.     endif
  841.  
  842.     if( gPeakWidthFactor == 0 )
  843.         gPeakWidthFactor= 3
  844.     endif
  845.  
  846.     String dfSav= GetDataFolder(1)
  847.     SetDataFolder :WMPeakFits:Current
  848.  
  849.     wave c= coef
  850.     wave mc= masterCoef
  851.  
  852.     String bname= "Peak",fname                // basename for individual peak waves
  853.     String func
  854.  
  855.     Variable i=0,xmin,xmax,pos,width,amp,shape
  856.     do
  857.         fname= bname+num2istr(i+1)        // peak numbers start with 1
  858.         Make/O/N=100 $fname
  859.         Wave w= $fname
  860.         
  861.         pos= mc[6+4*i+1]                // position of peak
  862.         if( g1Width )
  863.             width= mc[8]                // width of first peak
  864.         else
  865.             width= mc[8+4*i]            // width of this peak
  866.         endif
  867.         
  868.         // Bracket peak position but don't go all the way to the ends to avoid unnecessary long runs of zero
  869.         Variable lXMax= gXMax, lXMin= gXMin
  870.         if( lXMax < lXMin )                            // in case axis is reversed
  871.             lXMax= gXMin
  872.             lXMin= gXMax
  873.         endif
  874.         width= abs(width)
  875.         xmax= min(lXMax,pos+gPeakWidthFactor*width)
  876.         xmin= max(lXMin,pos-gPeakWidthFactor*width)
  877.         
  878.  
  879.         SetScale x,xmin,xmax,"",w
  880.         Duplicate/O c,tempcoef
  881.         
  882.         amp= CalcAmpFromMC(i,mc)
  883.         width= CalcWidthFromMC(i,mc)
  884.         shape= CalcShapeFromMC(i,mc)
  885.         // don't need position since that is never common nor in need of munging
  886.  
  887.         if( gFitType==0 )    // Gaussian = k0*exp(-((x-k1)/k2)^2)
  888.             func= "GaussFit"
  889.             tempcoef= {0,amp,pos,width}
  890.         endif
  891.         if( gFitType==1 )    // Lorentzian = k0*/( (x-k1)^2 + k2 )
  892.             func= "LorentzianFit"
  893.             tempcoef= {0,amp,pos,width}
  894.         endif
  895.         if( gFitType==2 )    // VoigtFit = k0*Voigt(k1*(x-k2),k3)
  896.             func= "VoigtFit"
  897.             tempcoef= {0,amp,width,pos,shape}
  898.         endif
  899.         if( gUseXFUNCs == 0 )
  900.             func= "f"+func
  901.         endif
  902.         Execute fname+"= "+func+"(tempcoef,x)"
  903.         CheckDisplayed/W=$WinName(0, 1) :::$gYDataName
  904.         if( V_Flag == 1 )
  905.             CheckDisplayed/W=$WinName(0, 1) w
  906.             if( V_Flag != 1 )
  907.                 AppendToGraph w
  908.             endif
  909.         endif
  910.         i += 1
  911.     while(i<gNumPeaks)
  912.     KillWaves tempcoef
  913.     SetDataFolder dfSav
  914.     
  915.     TrimExcessPeaks()        // from previous runs
  916. end
  917.  
  918.  
  919.  
  920. Function SetAPeak()
  921.  
  922.     if( CheckPeakPackage() )
  923.         return 0
  924.     endif
  925.  
  926.     wave w= $":WMPeakFits:Current:masterCoef"
  927.     wave hw= $":WMPeakFits:Current:masterCoefHold"
  928.     
  929.     NVAR gCurPeak= root:Packages:WMmpFitting:gCurPeak
  930.     NVAR gPeakAmp= root:Packages:WMmpFitting:gPeakAmp
  931.     NVAR gPeakPos= root:Packages:WMmpFitting:gPeakPos
  932.     NVAR gPeakWidth= root:Packages:WMmpFitting:gPeakWidth
  933.     NVAR gVoigtShape= root:Packages:WMmpFitting:gVoigtShape    
  934.     
  935.     variable i=6+4*(gCurPeak-1)
  936.     w[i]={gPeakAmp,gPeakPos,gPeakWidth,gVoigtShape}
  937.     ControlInfo/W=FitSetupPanel checkAmp; hw[i]= V_value
  938.     ControlInfo/W=FitSetupPanel  checkPos; hw[i+1]= V_value
  939.     ControlInfo/W=FitSetupPanel  checkWid; hw[i+2]= V_value
  940.     ControlInfo/W=FitSetupPanel  checkVS; hw[i+3]= V_value
  941.     CalculateData()
  942. End
  943.  
  944. Function UpdateCurSettings()
  945.     wave w= $":WMPeakFits:Current:masterCoef"
  946.     wave hw= $":WMPeakFits:Current:masterCoefHold"
  947.  
  948.     NVAR gCurPeak= root:Packages:WMmpFitting:gCurPeak
  949.     NVAR gPeakPos= root:Packages:WMmpFitting:gPeakPos
  950.     NVAR gPeakWidth= root:Packages:WMmpFitting:gPeakWidth
  951.     NVAR gVoigtShape= root:Packages:WMmpFitting:gVoigtShape
  952.     NVAR gPeakAmp= root:Packages:WMmpFitting:gPeakAmp
  953.     NVAR gNumPeaks= root:Packages:WMmpFitting:gNumPeaks
  954.     
  955.     gNumPeaks= (numpnts(w)-6)/4
  956.     if( gCurPeak > gNumPeaks )
  957.         gCurPeak= 1
  958.     endif
  959.     SetVariable SetPkNum limits={1,gNumPeaks,1},win=FitSetupPanel
  960.  
  961.     Variable i= 6+4*(gCurPeak-1)
  962.     gPeakAmp=w[i];gPeakPos= w[i+1]; gPeakWidth= w[i+2] ; gVoigtShape= w[i+3]
  963.     CheckBox checkAmp value=hw[i],win=FitSetupPanel
  964.     CheckBox checkPos value=hw[i+1],win=FitSetupPanel
  965.     CheckBox checkWid value=hw[i+2],win=FitSetupPanel
  966.     CheckBox checkVS value=hw[i+3],win=FitSetupPanel
  967. End
  968.  
  969. Function SetVarProcNPeaks(ctrlName,varNum,varStr,varName) : SetVariableControl
  970.     String ctrlName
  971.     Variable varNum
  972.     String varStr
  973.     String varName
  974.  
  975.     NVAR gNumPeaks= root:Packages:WMmpFitting:gNumPeaks
  976.     NVAR gCurPeak= root:Packages:WMmpFitting:gCurPeak
  977.  
  978.     SetVariable SetPkNum limits={1,gNumPeaks,1}
  979.     
  980.     if( exists(":WMPeakFits:Current:masterCoef") == 0 )
  981.         return 0
  982.     endif
  983.     
  984.     DoSetDataRange()
  985.  
  986.     wave w= $":WMPeakFits:Current:masterCoef"
  987.     Variable oldNpeaks= (numpnts(w)-6)/4,i
  988.     Redimension/N=(6+4*gNumPeaks) w,$":WMPeakFits:Current:masterCoefHold"
  989.     if( oldNpeaks < gNumPeaks )
  990.         do
  991.             i= 6+4*(oldNpeaks)
  992.             w[i]= w[i-4]*0.9                    // new peak amp smaller than last
  993.             w[i+1]= w[i-3]+2*w[i-2]        // new pos one peak width from last
  994.             w[i+2]= w[i-2]                    // make sure width parameter is not zero (else get nan from gauss)
  995.             w[i+3]= 1                            // always a reasonable guess for voigt
  996.             oldNpeaks+=1
  997.         while(oldNpeaks<gNumPeaks)
  998.     else
  999.         if( gCurPeak > gNumPeaks )
  1000.             gCurPeak= gNumPeaks
  1001.             UpdateCurSettings()
  1002.         endif
  1003.     endif
  1004.     CalculateData()
  1005. End
  1006.  
  1007. // Speical purpose to gen hold string from the hold wave
  1008. Function/S GenHoldStrForFitProc(w)
  1009.     Wave w
  1010.  
  1011.     variable ntot= numpnts(w)
  1012.     
  1013.     String s=""
  1014.     Variable i=0
  1015.     do
  1016.         if( w[i] == 0 )
  1017.             s += "0"
  1018.         else
  1019.             s += "1"
  1020.         endif
  1021.         i+=1
  1022.     while(i<ntot)
  1023.     return s
  1024. end
  1025.  
  1026. Function fitProc(ctrlName) : ButtonControl
  1027.     String ctrlName
  1028.  
  1029.     if( CheckPeakPackage() )
  1030.         return 0
  1031.     endif
  1032.  
  1033.      String func= ""
  1034.  
  1035.      CalculateCoef()
  1036.  
  1037.     NVAR gFitType= root:Packages:WMmpFitting:gFitType
  1038.     NVAR g1Width= root:Packages:WMmpFitting:g1Width
  1039.     NVAR g1Shape= root:Packages:WMmpFitting:g1Shape
  1040.     NVAR gUseXFUNCs= root:Packages:WMmpFitting:gUseXFUNCs
  1041.     NVAR gDoBaseline= root:Packages:WMmpFitting:gDoBaseline
  1042.     SVAR gYDataName= root:Packages:WMmpFitting:gYDataName
  1043.     SVAR gXDataName= root:Packages:WMmpFitting:gXDataName
  1044.     SVAR gFitDataName= root:Packages:WMmpFitting:gFitDataName
  1045.     SVAR gResidsName= root:Packages:WMmpFitting:gResidsName
  1046.     NVAR gChiSquare= root:Packages:WMmpFitting:gChiSquare
  1047.  
  1048.     NVAR gRangeBegin= :WMPeakFits:Current:gRangeBegin
  1049.     NVAR gRangeEnd= :WMPeakFits:Current:gRangeEnd
  1050.  
  1051.     if( gFitType==0 )    // Gaussian = k0*exp(-((x-k1)/k2)^2)
  1052.         if( g1Width )
  1053.             func= "GaussFit1Width"
  1054.         else
  1055.             func= "GaussFit"
  1056.         endif
  1057.     endif
  1058.     if( gFitType==1 )    // Lorentzian = k0*/( (x-k1)^2 + k2 )
  1059.         if( g1Width )
  1060.             func= "LorentzianFit1Width"
  1061.         else
  1062.             func= "LorentzianFit"
  1063.         endif
  1064.     endif
  1065.     if( gFitType==2 )    // VoigtFit = k0*Voigt(k1*(x-k2),k3)
  1066.         if( g1Width )    // implies 1 Shape also
  1067.             func= "VoigtFit1Shape1Width"
  1068.         else
  1069.             if( g1Shape )
  1070.                 func= "VoigtFit1Shape"
  1071.             else
  1072.                 func= "VoigtFit"
  1073.             endif
  1074.         endif
  1075.     endif
  1076.     if( gUseXFUNCs == 0 )
  1077.         func= "f"+func
  1078.     endif
  1079.     
  1080.     String dfSav= GetDataFolder(1)
  1081.     SetDataFolder :WMPeakFits:Current
  1082.     
  1083.     Wave cw= coef
  1084.     Wave dy= :::$gYDataName
  1085.     Wave dx= :::$gXDataName        // may be NULL
  1086.     Wave fw= :::$gFitDataName
  1087.     Wave rw= :::$gResidsName
  1088.     
  1089.     String holdStrName= gYDataName+"_HoldStr"
  1090.     String/G $holdStrName= GenHoldStrForFitProc($"coefHold")    // we use a variable rather than creating literal string in command so unlimited peaks will not create too long a command
  1091.  
  1092.     String s= func
  1093.     if( gDoBaseline )
  1094.         s += "BL"
  1095.     endif
  1096.     s += " " + GetWavesDataFolder(cw,4)+" "+GetWavesDataFolder(dy,4)+"["+num2str(gRangeBegin)+","+num2str(gRangeEnd)+"]"
  1097.     if( cmpstr(gXDataName,"_calculated_") != 0 )
  1098.         s += " /X= "+GetWavesDataFolder(dx,4)
  1099.     endif
  1100.     s += " /D="+GetWavesDataFolder(fw,4)
  1101.     s=  "FuncFit"+"/H="+PossiblyQuoteName(holdStrName)+" "+s
  1102.  
  1103.     print s
  1104.     Execute s
  1105.  
  1106.     SetDataFolder dfSav
  1107.     
  1108.     rw[gRangeBegin,gRangeEnd]= dy-fw
  1109.  
  1110.     gChiSquare= CalcChiSqr(rw)
  1111.     UpdateMasterCoef();UpdateCurSettings()
  1112.     UpdateIndividualPeaks()
  1113. End
  1114.  
  1115. // given a residuals wave, calculate chi squared
  1116. Function CalcChiSqr(residsw)
  1117.     Wave residsw
  1118.  
  1119.     NVAR gRangeBegin= :WMPeakFits:Current:gRangeBegin
  1120.     NVAR gRangeEnd= :WMPeakFits:Current:gRangeEnd
  1121.     
  1122.     // I'd like to check here if the residsw is null or not but can't figure
  1123.     // out how.
  1124.     Variable chisq=0,i=gRangeBegin,npts= gRangeEnd+1
  1125.     do
  1126.         chisq += residsw[i]^2
  1127.         i+=1
  1128.     while(i<npts)
  1129.     return chisq
  1130. end
  1131.  
  1132. Function foo()
  1133.     SVAR gResidsName= root:Packages:WMmpFitting:gResidsName
  1134.     NVAR gChiSquare= root:Packages:WMmpFitting:gChiSquare
  1135.     gChiSquare= CalcChiSqr($gResidsName)
  1136.     print gChiSquare
  1137. end
  1138.  
  1139.  
  1140. Function SetPeakNumProc(ctrlName,varNum,varStr,varName) : SetVariableControl
  1141.     String ctrlName
  1142.     Variable varNum
  1143.     String varStr
  1144.     String varName
  1145.  
  1146.     if( CheckPeakPackage() )
  1147.         return 0
  1148.     endif
  1149.  
  1150.     UpdateCurSettings()
  1151. End
  1152.  
  1153. Proc PopProcFunc(ctrlName,popNum,popStr) : PopupMenuControl
  1154.     String ctrlName
  1155.     Variable popNum
  1156.     String popStr
  1157.  
  1158.     if( CheckPeakPackage() )
  1159.         return
  1160.     endif
  1161.  
  1162.     root:Packages:WMmpFitting:gFitType= popNum-1
  1163.     ValidateShapeForVoigt()
  1164.     CalculateData()
  1165. End
  1166.  
  1167.  
  1168. Proc CheckProcUseXFUNCs(ctrlName,checked) : CheckBoxControl
  1169.     String ctrlName
  1170.     Variable checked
  1171.  
  1172.     root:Packages:WMmpFitting:gUseXFUNCs= checked
  1173. End
  1174.  
  1175. Proc CheckProc1Width(ctrlName,checked) : CheckBoxControl
  1176.     String ctrlName
  1177.     Variable checked
  1178.  
  1179.     root:Packages:WMmpFitting:g1Width= checked
  1180.     ValidateShapeForVoigt()
  1181. End
  1182.  
  1183. Function ValidateShapeForVoigt()
  1184.     NVAR gFitType= root:Packages:WMmpFitting:gFitType
  1185.     NVAR g1Width= root:Packages:WMmpFitting:g1Width
  1186.     NVAR g1Shape= root:Packages:WMmpFitting:g1Shape
  1187.     if( gFitType==2 )    // VoigtFit
  1188.         if( (g1Width!=0) %& (g1Shape==0) )    // illegal combo?
  1189.             CheckBox checkCS,value=1
  1190.             g1Shape= 1
  1191.         endif
  1192.     endif
  1193. end
  1194.  
  1195.  
  1196. Proc CheckProc1Shape(ctrlName,checked) : CheckBoxControl
  1197.     String ctrlName
  1198.     Variable checked
  1199.  
  1200.     root:Packages:WMmpFitting:g1Shape= checked
  1201.     ValidateShapeForVoigt()
  1202. End
  1203.  
  1204. Proc CheckProcDoBaseline(ctrlName,checked) : CheckBoxControl
  1205.     String ctrlName
  1206.     Variable checked
  1207.  
  1208.     root:Packages:WMmpFitting:gDoBaseline= checked
  1209. End
  1210.  
  1211. Proc CheckProcHold(ctrlName,checked) : CheckBoxControl
  1212.     String ctrlName
  1213.     Variable checked
  1214.  
  1215.     SetAPeak()
  1216. End
  1217.  
  1218. Function ButtonProcAmpFromCsrA(ctrlName) : ButtonControl
  1219.     String ctrlName
  1220.  
  1221.     if( CheckPeakPackage() )
  1222.         return 0
  1223.     endif
  1224.  
  1225.     wave w= $":WMPeakFits:Current:masterCoef"
  1226.     NVAR gCurPeak= root:Packages:WMmpFitting:gCurPeak
  1227.     Variable i= 6+4*(gCurPeak-1)
  1228.     do
  1229.         if( cmpstr(ctrlName,"b0") == 0 )
  1230.             w[i]= vcsr(A)
  1231.             break
  1232.         endif
  1233.         if( cmpstr(ctrlName,"b1") == 0 )
  1234.             w[i+1]= hcsr(A)
  1235.             break
  1236.         endif
  1237.         if( cmpstr(ctrlName,"b2") == 0 )
  1238.             w[i+2]= abs(hcsr(A)-hcsr(B))
  1239.             break
  1240.         endif
  1241.     while(0)
  1242.     CalculateData()
  1243.     UpdateCurSettings()
  1244. End
  1245.  
  1246. Proc ButtonProcNewGraph(ctrlName) : ButtonControl
  1247.     String ctrlName
  1248.  
  1249.     if( CheckPeakPackage() )
  1250.         return
  1251.     endif
  1252.  
  1253.     MakeGraph()
  1254. End
  1255.  
  1256. Function ResetAxisRange()
  1257.     NVAR gRangeBegin= :WMPeakFits:Current:gRangeBegin
  1258.     NVAR gRangeEnd= :WMPeakFits:Current:gRangeEnd
  1259.  
  1260.     SVAR gYDataName= root:Packages:WMmpFitting:gYDataName
  1261.     SVAR gXDataName= root:Packages:WMmpFitting:gXDataName
  1262.  
  1263.     Variable vmin,vmax
  1264.  
  1265.     if( cmpstr(gXDataName,"_calculated_") == 0 )
  1266.         vmin= pnt2x($gYDataName,gRangeBegin)
  1267.         vmax= pnt2x($gYDataName,gRangeEnd)
  1268.     else
  1269.         Wave w= $gXDataName
  1270.         vmin=w[gRangeBegin]
  1271.         vmax=w[gRangeEnd]
  1272.     endif
  1273.  
  1274.     if( strlen(WinName(0, 1)) != 0 )
  1275.         CheckDisplayed/W=$WinName(0, 1) $gYDataName
  1276.         if( V_Flag )
  1277.             SetAxis bottom,vmin,vmax
  1278.         endif
  1279.     endif
  1280.     printf "Range reset from saved data: points= [%d,%d] ( equivalent to x= (%g,%g) )\r",gRangeBegin,gRangeEnd,vmin,vmax
  1281. end
  1282.  
  1283.  
  1284. Function DoSetDataRange()
  1285.     NVAR gRangeBegin= :WMPeakFits:Current:gRangeBegin
  1286.     NVAR gRangeEnd= :WMPeakFits:Current:gRangeEnd
  1287.  
  1288.     SVAR gYDataName= root:Packages:WMmpFitting:gYDataName
  1289.     SVAR gXDataName= root:Packages:WMmpFitting:gXDataName
  1290.  
  1291.     gRangeBegin= 0; gRangeEnd= numpnts($gYDataName)-1;
  1292.     
  1293.     Variable te= gRangeEnd
  1294.     Variable V_Flag= 0
  1295.  
  1296.     if( strlen(WinName(0, 1)) != 0 )
  1297.         CheckDisplayed/W=$WinName(0, 1) $gYDataName
  1298.     endif
  1299.     if( V_Flag )
  1300.         GetAxis /Q bottom
  1301.         if( cmpstr(gXDataName,"_calculated_") == 0 )
  1302.             gRangeBegin= x2pnt($gYDataName,V_min)
  1303.             gRangeEnd= x2pnt($gYDataName,V_max)
  1304.         else
  1305.             gRangeBegin=BinarySearch($gXDataName,V_min)
  1306.             gRangeEnd=BinarySearch($gXDataName,V_max)
  1307.             if( gRangeEnd == -2 )
  1308.                 gRangeEnd= te
  1309.             endif
  1310.         endif
  1311.         if( gRangeBegin<0 )
  1312.             gRangeBegin= 0;
  1313.         endif
  1314.         if( gRangeEnd>te )
  1315.             gRangeEnd= te
  1316.         endif
  1317.         printf "Range set from graph: points= [%d,%d] ( equivalent to x= (%g,%g) )\r",gRangeBegin,gRangeEnd,V_min,V_max
  1318.     else
  1319.         printf "Range set to full extent of data (not graphed yet)\r"
  1320.     endif
  1321. End
  1322.  
  1323.  
  1324. Function ButtonProcSet(ctrlName) : ButtonControl
  1325.     String ctrlName
  1326.     
  1327.     NewDataFolder/O WMPeakFits                // contains material about one data set (names of data, sub-range DFs)
  1328.     NewDataFolder/O :WMPeakFits:Current        // contains material specific to a sub-range of one data set (peaks, coefs etc)
  1329.     
  1330.     SVAR gCurDataFolder= root:Packages:WMmpFitting:gCurDataFolder
  1331.     SVAR gFitDataName= root:Packages:WMmpFitting:gFitDataName
  1332.     SVAR gXDataName= root:Packages:WMmpFitting:gXDataName
  1333.     SVAR gYDataName= root:Packages:WMmpFitting:gYDataName
  1334.     SVAR gResidsName= root:Packages:WMmpFitting:gResidsName
  1335.     NVAR gNumPeaks= root:Packages:WMmpFitting:gNumPeaks
  1336.     NVAR gCurPeak= root:Packages:WMmpFitting:gCurPeak
  1337.  
  1338.     Variable/G :WMPeakFits:Current:gRangeBegin,:WMPeakFits:Current:gRangeEnd
  1339.     NVAR gRangeBegin= :WMPeakFits:Current:gRangeBegin
  1340.     NVAR gRangeEnd= :WMPeakFits:Current:gRangeEnd
  1341.  
  1342.     Variable/G :WMPeakFits:Current:gXMin,:WMPeakFits:Current:gXMax
  1343.     NVAR gXMin= :WMPeakFits:Current:gXMin
  1344.     NVAR gXMax= :WMPeakFits:Current:gXMax
  1345.  
  1346.     String/G :WMPeakFits:yDataName,:WMPeakFits:xDataName
  1347.     SVAR yDataName= :WMPeakFits:yDataName
  1348.     SVAR xDataName= :WMPeakFits:xDataName
  1349.  
  1350.     ControlInfo popupYData
  1351.     gYDataName= S_value
  1352.     ControlInfo popupXData
  1353.     gXDataName=  S_value
  1354.     
  1355.     if( (strlen(gYDataName) *strlen(gXDataName)) == 0 )
  1356.         DoAlert 0,"Choose X and Y data first"
  1357.         return 0
  1358.     endif
  1359.  
  1360.     gCurDataFolder= GetDataFolder(1)
  1361.  
  1362.     yDataName= gYDataName    // for revisit feature when we have been working on a different data set
  1363.     xDataName= gXDataName
  1364.     
  1365.     Variable reset    // used to check if we are resetting using the same data or if we are starting fresh
  1366.     
  1367.     reset= CmpStr(gFitDataName, "fit_"+gYDataName)==0
  1368.     reset *= CmpStr(gResidsName, "res_"+gYDataName)==0
  1369.     if( reset )
  1370.         reset *= numpnts($gYDataName)==numpnts($gResidsName)
  1371.     endif
  1372.     
  1373.     if( reset == 0 )
  1374.         gFitDataName= "fit_"+gYDataName
  1375.         gResidsName= "res_"+gYDataName
  1376.         Duplicate/O $gYDataName,$gFitDataName,$gResidsName
  1377.         Wave w= $gResidsName
  1378.         w= NaN
  1379.         Wave w= $gFitDataName
  1380.         w= NaN
  1381.         
  1382.         printf "Set Y data= %s, X data= %s, fit wave= %s, residuals= %s\r",gYDataName,gXDataName,gFitDataName,gResidsName
  1383.     else
  1384.         print "Reset using same data"
  1385.     endif
  1386.     
  1387.     DoSetDataRange()
  1388.     
  1389.     if( gNumPeaks == 0 )            // user hasn't set this yet
  1390.         gCurPeak= 1
  1391.         gNumPeaks= 2                // arbitrary first
  1392.         SetVariable SetPkNum limits={1,gNumPeaks,1}
  1393.     endif
  1394.     
  1395.     Duplicate/O $gYDataName,$":WMPeakFits:Current:masterCoef"    // force same number type
  1396.     Make/O/B $":WMPeakFits:Current:masterCoefHold"={1,1}
  1397.     Redimension/N=(6+4*gNumPeaks) $":WMPeakFits:Current:masterCoef",$":WMPeakFits:Current:masterCoefHold"
  1398.  
  1399.     wave cw= $":WMPeakFits:Current:masterCoef"
  1400.     Variable xmin,xmax
  1401.     if( cmpstr(gXDataName,"_calculated_") == 0 )
  1402.         xmin= pnt2x($gYDataName,gRangeBegin)
  1403.         xmax= pnt2x($gYDataName,gRangeEnd)
  1404.     else
  1405.         WaveStats/Q/R=[gRangeBegin,gRangeEnd] $gXDataName
  1406.         xmin=V_min
  1407.         xmax=V_max
  1408.     endif
  1409.     gXMin= xmin
  1410.     gXMax= xmax
  1411.  
  1412.     WaveStats/Q/R=[gRangeBegin,gRangeEnd] $gYDataName
  1413.     cw[0]= (xmin+xmax)/2
  1414.     cw[1]= xmax-xmin
  1415.     if( abs(V_min) < 0.01*abs(V_max) )        // protect against near zero baseline (singlar matrix)
  1416.         cw[2]= 0.01*V_max                // estimate of offset
  1417.     else
  1418.         cw[2]= V_min                // estimate of offset
  1419.     endif
  1420.     cw[3]= (V_max-V_min)*0.01    // fairly arbitrary estimate for ...
  1421.     cw[4]= cw[3]                // coeff of x
  1422.     cw[5]= cw[3]                // coeff of x^2
  1423.     cw[6]= cw[3]                // coeff of x^3
  1424.     
  1425.     Variable i,cp=1,delta= (xmax-xmin)/(gNumPeaks+1)
  1426.     do
  1427.          i=6+4*(cp-1)
  1428.         cw[i]= {V_max-V_min,xmin+cp*delta,delta/10,1}
  1429.         cp += 1
  1430.     while( cp<=gNumPeaks)
  1431.     UpdateCurSettings()
  1432.     CalculateData()
  1433. End
  1434.  
  1435. Proc MakeGraph()
  1436.     PauseUpdate; Silent 1        // building window...
  1437.  
  1438.     String gXDataName= root:Packages:WMmpFitting:gXDataName
  1439.     String gYDataName= root:Packages:WMmpFitting:gYDataName
  1440.     String gFitDataName= root:Packages:WMmpFitting:gFitDataName
  1441.     String gResidsName= root:Packages:WMmpFitting:gResidsName
  1442.     
  1443.     Variable isYN= cmpstr(gXDataName,"_calculated_") == 0
  1444.  
  1445.     if( isYN )
  1446.         Display /W=(5,42,410,401) $gYDataName,$gFitDataName
  1447.         Append/L=lr $gResidsName
  1448.     else
  1449.         Display /W=(5,42,410,401) $gYDataName,$gFitDataName vs $gXDataName
  1450.         Append/L=lr $gResidsName vs $gXDataName
  1451.     endif
  1452.     ModifyGraph margin(left)=73,wbRGB=(49151,65535,49151),gbRGB=(49151,60031,65535)
  1453.     ModifyGraph mode($gYDataName)=3,mode($gResidsName)=2
  1454.     ModifyGraph marker($gYDataName)=8,marker($gResidsName)=19
  1455.     ModifyGraph lSize($gFitDataName)=2,lSize($gResidsName)=2
  1456.     ModifyGraph rgb($gFitDataName)=(0,0,65535)
  1457.     ModifyGraph msize($gYDataName)=2,msize($gResidsName)=2
  1458.     ModifyGraph mirror(left)=1,mirror(lr)=1
  1459.     ModifyGraph nticks(left)=4,nticks(lr)=2
  1460.     ModifyGraph minor=1
  1461.     ModifyGraph lowTrip(lr)=0.001
  1462.     ModifyGraph standoff(left)=0,standoff(bottom)=0
  1463.     ModifyGraph lblPos(left)=68,lblPos(lr)=68
  1464.     ModifyGraph freePos(lr)=0
  1465.     ModifyGraph axisEnab(left)={0,0.75}
  1466.     ModifyGraph axisEnab(lr)={0.8,1}
  1467.     Label left "Amplitude"
  1468.     Label bottom "Wavelength, \\U"
  1469.     Label lr "Residuals"
  1470.     SetAxis/A/N=1 left
  1471.     SetAxis/A bottom
  1472.     SetAxis/A/N=1/E=2 lr
  1473. EndMacro
  1474.  
  1475.  
  1476. Proc SetVarProcCoef(ctrlName,varNum,varStr,varName) : SetVariableControl
  1477.     String ctrlName
  1478.     Variable varNum
  1479.     String varStr
  1480.     String varName
  1481.  
  1482.     SetAPeak()
  1483. End
  1484.  
  1485. Proc ProcNextPeak(ctrlName) : ButtonControl
  1486.     String ctrlName
  1487.  
  1488.     root:Packages:WMmpFitting:gCurPeak= mod(root:Packages:WMmpFitting:gCurPeak,root:Packages:WMmpFitting:gNumPeaks)+1
  1489.     UpdateCurSettings()
  1490.     SetCursorsForCurPeak()
  1491. End
  1492.  
  1493. Proc BProcDone(ctrlName) : ButtonControl
  1494.     String ctrlName
  1495.  
  1496.     KillControl gb0
  1497.     KillControl gb1
  1498.     KillControl gb2
  1499.     ControlBar 0
  1500. End
  1501.  
  1502. Proc BProcSaveSet(ctrlName) : ButtonControl
  1503.     String ctrlName
  1504.  
  1505.     if( CheckPeakPackage() )
  1506.         return
  1507.     endif
  1508.  
  1509.     Duplicate/O $":WMPeakFits:Current:masterCoef" $(":WMPeakFits:Current:CoefSet"+num2istr(root:Packages:WMmpFitting:gSaveSet))
  1510.     Duplicate/O $":WMPeakFits:Current:masterCoefHold" $(":WMPeakFits:Current:CoefHoldSet"+num2istr(root:Packages:WMmpFitting:gSaveSet))
  1511. End
  1512.  
  1513. Proc PProcRecall(ctrlName,popNum,popStr) : PopupMenuControl
  1514.     String ctrlName
  1515.     Variable popNum
  1516.     String popStr
  1517.  
  1518.     if( CheckPeakPackage() )
  1519.         return
  1520.     endif
  1521.     
  1522.     Duplicate/O $":WMPeakFits:Current:"+popStr $":WMPeakFits:Current:masterCoef" 
  1523.     root:Packages:WMmpFitting:gSaveSet= str2num(popStr[strlen("CoefSet"),100])
  1524.     Duplicate/O $(":WMPeakFits:Current:CoefHoldSet"+num2istr(root:Packages:WMmpFitting:gSaveSet)), $":WMPeakFits:Current:masterCoefHold" 
  1525.     
  1526.     Variable npks= (numpnts($":WMPeakFits:Current:masterCoef")-6)/4    
  1527.     root:Packages:WMmpFitting:gNumPeaks= npks    // NOTE: done in two steps because previous rhs would have been evaluted in context of DF= root:Packages: etc
  1528.     UpdateCurSettings()
  1529.     CalculateData()
  1530.     SetVariable SetPkNum limits={1,root:Packages:WMmpFitting:gNumPeaks,1}
  1531. End
  1532.  
  1533. Function/S ListCoefSetWaves()
  1534.     if( !DataFolderExists(":WMPeakFits:Current") )
  1535.         return ""
  1536.     endif
  1537.     SetDataFolder :WMPeakFits:Current
  1538.     String s= WaveList("CoefSet*",";","")
  1539.     SetDataFolder :::
  1540.     return s
  1541. end
  1542.  
  1543. Window FitSetupPanel() : Panel
  1544.     PauseUpdate; Silent 1        // building window...
  1545.     String dfSav= GetDataFolder(1)
  1546.     
  1547.     SetDataFolder root:Packages:WMmpFitting
  1548.  
  1549.     NewPanel /W=(302,39,529,445)
  1550.     ModifyPanel cbRGB=(32769,65535,32768)
  1551.     SetDrawLayer UserBack
  1552.     SetDrawEnv rounding= 20
  1553.     DrawRRect 9,15,217,84
  1554.     SetDrawEnv fstyle= 1,textrgb= (0,0,65535)
  1555.     DrawText 15,106,"Initial Values"
  1556.     SetDrawEnv rounding= 20
  1557.     DrawRRect 9,106,217,249
  1558.     DrawLine 8,130,214,130
  1559.     SetDrawEnv fsize= 10,textxjust= 2,textyjust= 1
  1560.     DrawText 69,119,"For Peak #"
  1561.     SetDrawEnv fname= "Geneva",fsize= 9,textxjust= 2,textyjust= 1
  1562.     DrawText 70,144,"Amplitude:"
  1563.     SetDrawEnv fname= "Geneva",fsize= 9,textxjust= 2,textyjust= 1
  1564.     DrawText 70,163,"Position:"
  1565.     SetDrawEnv fname= "Geneva",fsize= 9,textxjust= 2,textyjust= 1
  1566.     DrawText 70,184,"Width:"
  1567.     SetDrawEnv fname= "Geneva",fsize= 9,textxjust= 2,textyjust= 1
  1568.     DrawText 70,203,"Voigt Shape:"
  1569.     SetDrawEnv rounding= 20
  1570.     DrawRRect 7,277,218,373
  1571.     DrawLine 178,106,178,219
  1572.     SetDrawEnv fsize= 9,textxjust= 1,textyjust= 1
  1573.     DrawText 193,114,"From"
  1574.     SetDrawEnv fsize= 9,textxjust= 1,textyjust= 1
  1575.     DrawText 196,123,"cursor"
  1576.     SetDrawEnv fsize= 10,textxjust= 2,textyjust= 1
  1577.     DrawText 122,118,"of"
  1578.     SetDrawEnv fstyle= 1,textrgb= (0,0,65535),textxjust= 1
  1579.     DrawText 31,16,"Data"
  1580.     DrawLine 9,219,215,219
  1581.     SetDrawEnv fstyle= 1,textrgb= (0,0,65535)
  1582.     DrawText 17,275,"Fitting Function"
  1583.     SetDrawEnv fname= "Geneva",fsize= 9,textrot= 90
  1584.     DrawText 163,127,"Hold"
  1585.     SetVariable setvar0,pos={125,111},size={27,15},proc=SetVarProcNPeaks,title=" "
  1586.     SetVariable setvar0,limits={1,1000,0},value=gNumPeaks
  1587.     SetVariable SetPkNum,pos={73,111},size={37,15},proc=SetPeakNumProc,title=" "
  1588.     SetVariable SetPkNum,limits={1,4,1},value=gCurPeak
  1589.     SetVariable setvar2,pos={73,137},size={87,13},proc=SetVarProcCoef,title=" "
  1590.     SetVariable setvar2,fSize=10,limits={-INF,INF,0},value=gPeakAmp
  1591.     SetVariable setvar3,pos={73,156},size={87,13},proc=SetVarProcCoef,title=" "
  1592.     SetVariable setvar3,fSize=10,format="%g",limits={-INF,INF,0},value=gPeakPos
  1593.     SetVariable setvar4,pos={73,177},size={87,13},proc=SetVarProcCoef,title=" "
  1594.     SetVariable setvar4,fSize=10,format="%g",limits={-INF,INF,0},value=gPeakWidth
  1595.     Button DoFitButton,pos={51,377},size={114,25},proc=fitProc,title="Do Fit"
  1596.     SetVariable setvar5,pos={73,197},size={87,13},proc=SetVarProcCoef,title=" "
  1597.     SetVariable setvar5,fSize=10,limits={0,INF,0},value=gVoigtShape
  1598.     PopupMenu popupFunc,pos={21,283},size={149,19},proc=PopProcFunc,title="Function:"
  1599.     PopupMenu popupFunc,mode=1,value= #"\"Gaussian;Lorentzian;Voigt\""
  1600.     CheckBox checkBL,pos={22,306},size={80,20},proc=CheckProcDoBaseline,title="Baseline",value=0
  1601.     CheckBox checkCW,pos={124,306},size={80,20},proc=CheckProc1Width,title="1 width",value=0
  1602.     CheckBox checkCS,pos={124,328},size={80,20},proc=CheckProc1Shape,title="1 shape",value=0
  1603.     CheckBox checkUseX,pos={22,328},size={95,20},proc=CheckProcUseXFUNCs,title="use XFUNCs",value=0
  1604.     PopupMenu popupYData,pos={17,18},size={77,19},title="Y: "
  1605.     PopupMenu popupYData,mode=1,value= #"WaveList(\"*\",\";\",\"\")"
  1606.     PopupMenu popupXData,pos={17,40},size={85,19},title="X: "
  1607.     PopupMenu popupXData,mode=3,value= #"\"_calculated_;\"+WaveList(\"*\",\";\",\"\")"
  1608.     Button b0,pos={185,136},size={18,14},proc=ButtonProcAmpFromCsrA,title="A"
  1609.     Button b1,pos={185,155},size={18,14},proc=ButtonProcAmpFromCsrA,title="A"
  1610.     Button b2,pos={181,175},size={28,14},proc=ButtonProcAmpFromCsrA,title="A-B"
  1611.     Button button0,pos={83,62},size={50,17},proc=ButtonProcNewGraph,title="Graph"
  1612.     Button button1,pos={22,62},size={50,17},proc=ButtonProcSet,title="Set"
  1613.     Button bSave,pos={16,223},size={50,20},proc=BProcSaveSet,title="Save"
  1614.     SetVariable setvar1,pos={70,224},size={65,15},title="Set",format="%d"
  1615.     SetVariable setvar1,limits={0,10,1},value=gSaveSet
  1616.     PopupMenu popRecall,pos={144,223},size={64,19},proc=PProcRecall,title="Recall"
  1617.     PopupMenu popRecall,mode=0,value= #"ListCoefSetWaves()"
  1618.     ValDisplay valdisp0,pos={48,352},size={152,15},title="Chi Square"
  1619.     ValDisplay valdisp0,limits={0,0,0},barmisc={0,1000},value= #"root:Packages:WMmpFitting:gChiSquare"
  1620.     CheckBox checkAmp,pos={161,133},size={16,20},proc=CheckProcHold,title="",value=0
  1621.     CheckBox checkPos,pos={161,152},size={16,20},proc=CheckProcHold,title="",value=0
  1622.     CheckBox checkWid,pos={161,173},size={16,20},proc=CheckProcHold,title="",value=0
  1623.     CheckBox checkVS,pos={161,193},size={16,20},proc=CheckProcHold,title="",value=0
  1624.     SetDataFolder dfSav
  1625. EndMacro
  1626.  
  1627.